package com.java.demo.thread;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;

/**
 * @auther zhangwj
 * @date 2020/8/24 5:19 下午
 */
public class Demo6 {
    public static void main(String[] args) throws IOException {
        NIOServer nioServer = new NIOServer();
        nioServer.start();
    }
}


class NIOServer {
    private Selector selector;
    private ServerSocketChannel serverSocketChannel;

    NIOServer() throws IOException {
        System.out.println("初始化开始");
        selector = Selector.open();
        serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));
        serverSocketChannel.configureBlocking(false);
        SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        selectionKey.attach(new AcceptorHandler());
        System.out.println("初始化结束");
    }

    public void dispatch(SelectionKey selectionKey) {
        Handler handler = (Handler) selectionKey.attachment();
        if (handler != null) {
            handler.start();
        }
    }

    public void start() throws IOException {
        while (selector.select() > 0) {
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            for (SelectionKey selectionKey : selectionKeys) {
                dispatch(selectionKey);
            }
            selectionKeys.clear();
        }
    }

    class AcceptorHandler implements Handler {

        @Override
        public void start() {
            try {
                SocketChannel socketChannel = serverSocketChannel.accept();
                if (socketChannel != null) {
                    System.out.println("1111");
                    new EchoHandler(selector, socketChannel).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

interface Handler {

    void start();
}

class EchoHandler implements Handler {

    final SocketChannel channel;
    final SelectionKey selectionKey;
    final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
    static final int RECEIVING = 0, SENDING = 1;
    int state = RECEIVING;

    EchoHandler(Selector selector, SocketChannel c) throws IOException {
        channel = c;
        c.configureBlocking(false);
        //取得选择键，再设置感兴趣的IO事件
        selectionKey = channel.register(selector, 0);
        //将Handler自身作为选择键的附件
        selectionKey.attach(this);
        //注册Read就绪事件
        selectionKey.interestOps(SelectionKey.OP_READ);
        selector.wakeup();
    }

    @Override
    public void start() {
        try {
            if (state == SENDING) {
                //写入通道
                channel.write(byteBuffer);
                //写完后,准备开始从通道读,byteBuffer切换成写入模式
                byteBuffer.clear();
                //写完后,注册read就绪事件
                selectionKey.interestOps(SelectionKey.OP_READ);
                //写完后,进入接收的状态
                state = RECEIVING;
            } else if (state == RECEIVING) {
                //从通道读
                int length = 0;
                while ((length = channel.read(byteBuffer)) > 0) {
                    System.out.println(new String(byteBuffer.array(), 0, length));
                }
                //读完后，准备开始写入通道,byteBuffer切换成读取模式
                byteBuffer.flip();
                //读完后，注册write就绪事件
                selectionKey.interestOps(SelectionKey.OP_WRITE);
                //读完后,进入发送的状态
                state = SENDING;
            }
            //处理结束了, 这里不能关闭select key，需要重复使用
            //sk.cancel();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}